﻿using System;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;
using CommonServiceLocator.WindsorAdapter;
using Microsoft.Practices.ServiceLocation;
using NHibernate.Cfg;
using NHibernate.Event;
using NHibernate.Tool.hbm2ddl;
using SharpArch.Domain.Events;
using SharpArch.NHibernate;
using SharpArch.NHibernate.Web.Mvc;
using SharpArch.Web.Mvc.Castle;
using SharpArch.Web.Mvc.ModelBinder;
using ToyStore.Infrastructure;
using ToyStore.Infrastructure.NHibernateMaps;
using ToyStore.Web.Mvc.Authentication;
using ToyStore.Web.Mvc.CastleWindsor;
using ToyStore.Web.Mvc.Controllers;
using log4net.Config;

namespace ToyStore.Web.Mvc
{
	/// <summary>
	/// Represents the MVC Application
	/// </summary>
	/// <remarks>
	/// For instructions on enabling IIS6 or IIS7 classic mode, 
	/// visit http://go.microsoft.com/?LinkId=9394801
	/// </remarks>
	public class MvcApplication : HttpApplication
	{
		private WebSessionStorage webSessionStorage;

		/// <summary>
		/// Due to issues on IIS7, the NHibernate initialization must occur in Init().
		/// But Init() may be invoked more than once; accordingly, we introduce a thread-safe
		/// mechanism to ensure it's only initialized once.
		/// See http://msdn.microsoft.com/en-us/magazine/cc188793.aspx for explanation details.
		/// </summary>
		public override void Init()
		{
			base.Init();
			webSessionStorage = new WebSessionStorage(this);
		}

		/// <summary>
		/// Obsłużenie każdego żądania.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void Application_BeginRequest(object sender, EventArgs e)
		{
			NHibernateInitializer.Instance().InitializeNHibernateOnce(InitialiseNHibernateSessions);
		}

		/// <summary>
		/// Obsłużenie błędów.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void Application_Error(object sender, EventArgs e)
		{
			// Useful for debugging
			Exception ex = Server.GetLastError();
			var reflectionTypeLoadException = ex as ReflectionTypeLoadException;
		}

		/// <summary>
		/// Obsłużenie uruchamiania aplikacji.
		/// </summary>
		protected void Application_Start()
		{
			XmlConfigurator.Configure();

			ViewEngines.Engines.Clear();

			ViewEngines.Engines.Add(new RazorViewEngine());

			ModelBinders.Binders.DefaultBinder = new SharpModelBinder();

			//ModelValidatorProviders.Providers.Add(new ClientDataTypeModelValidatorProvider());

			InitializeServiceLocator();

			AreaRegistration.RegisterAllAreas();
			RouteRegistrar.RegisterRoutesTo(RouteTable.Routes);
		}

		/// <summary>
		/// Instantiate the container and add all Controllers that derive from
		/// WindsorController to the container.  Also associate the Controller
		/// with the WindsorContainer ControllerFactory.
		/// </summary>
		protected virtual void InitializeServiceLocator()
		{
			IWindsorContainer container = new WindsorContainer();

			ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));

			container.RegisterControllers(typeof (HomeController).Assembly);
			ComponentRegistrar.AddComponentsTo(container);

			var windsorServiceLocator = new WindsorServiceLocator(container);
			DomainEvents.ServiceLocator = windsorServiceLocator;
			ServiceLocator.SetLocatorProvider(() => windsorServiceLocator);
		}

		private void InitialiseNHibernateSessions()
		{
			NHibernateSession.ConfigurationCache = new NHibernateConfigurationFileCache();

			Configuration configuration = NHibernateSession.Init(
				webSessionStorage,
				new[] {Server.MapPath("~/bin/ToyStore.Infrastructure.dll")},
				new AutoPersistenceModelGenerator().Generate(),
				Server.MapPath("~/NHibernate.config"));

			// Listenery zdefiniowane w solucji do ustawiania dat dodawania, modyfikacji itp.
			configuration.SetListener(ListenerType.PreUpdate, new AuditEventListener());
			configuration.SetListener(ListenerType.PreInsert, new AuditEventListener());

			new SchemaUpdate(configuration).Execute(false, true);
			//new SchemaExport(configuration).Execute(true, true, false);
		}

		/// <summary>
		/// Autoryzacja.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void Application_AuthenticateRequest(object sender, EventArgs e)
		{
			if (Request.IsAuthenticated)
			{
				WebAuthentication.ApplyRightPrincipal();
			}
		}
	}
}